/**
 * 
 */
package coop.tecso.core.test.handlers.factory.impl;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.persistence.Column;
import javax.validation.constraints.Digits;

import org.apache.log4j.Logger;
import org.org.usurper.handlers.IHandler;
import org.org.usurper.model.SpecificPropertyDefinition;

import coop.tecso.core.test.handlers.UsurperHandlers;
import coop.tecso.core.test.handlers.factory.PropertyHandlerFactory;
import coop.test.exception.ContradictoryRestrictionsException;

/**
 * @author daniel
 * 
 */
public class AnnotationAwareGeneralHandlerFactory implements PropertyHandlerFactory {

	private PropertyHandlerFactory delegateDefaultFactory = new DefaultPropertyHandlerFactory();

	private static final Logger logger = Logger.getLogger(AnnotationAwareGeneralHandlerFactory.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.avritech.zapsaude.factory.PropertyHandlerFactory#build(java.lang.
	 * Class, java.beans.PropertyDescriptor)
	 */
	@Override
	public IHandler build(Class<?> contextualClass, PropertyDescriptor descriptor) {
		String propertyName = descriptor.getName();
		Class<?> propertyClass = descriptor.getPropertyType();
		int length = 0;
		Digits digitsAnnotiation = getAnnotation(Digits.class, descriptor, contextualClass);
		if (digitsAnnotiation != null && String.class.isAssignableFrom(propertyClass)) {
			length = digitsAnnotiation.integer();
		}
		Column columnAnnotation = getAnnotation(Column.class, descriptor, contextualClass);
		if (columnAnnotation != null && String.class.isAssignableFrom(propertyClass)) {
			int newLength = columnAnnotation.length();
			if (newLength != length && length != 0) {
				throw new ContradictoryRestrictionsException();
			}
			length = newLength;
		}
		if (length != 0) {
			return new UsurperHandlers.NumericStringHandler(new SpecificPropertyDefinition(contextualClass,
					propertyName), length);
		}
		return delegateDefaultFactory.build(contextualClass, descriptor);
	}

	private <T extends Annotation> T getAnnotation(Class<T> annotationType, PropertyDescriptor propertyDescriptor,
			Class<?> contextualClass) {
		System.out.println(contextualClass.getName());
		Field propertyField = null;
		T annotationObject = null;
		String name = propertyDescriptor.getName();
		try {
			propertyField = contextualClass.getField(name);
		} catch (Exception e) {
			try {
				propertyField = contextualClass.getDeclaredField(name);
			} catch (Exception e2) {
				logger.debug(String.format("Field: %s, not found for class %s. Defaulting to property lookup", name,
						contextualClass.getName()));
			}
		}
		if (propertyField != null) {
			annotationObject = propertyField.getAnnotation(annotationType);
		}
		if (annotationObject == null) {
			Method readMethod = propertyDescriptor.getReadMethod();
			if (readMethod != null) {
				annotationObject = readMethod.getAnnotation(annotationType);
			}
		}
		return annotationObject;
	}
}
